package com.github.icloudpay.pay.core.service.refund.wechat.service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.github.icloudpay.pay.core.feign.PayChannelConfigFeign;
import com.github.icloudpay.pay.core.inter.QueryRefundStatusService;
import com.github.icloudpay.pay.core.service.pay.wechat.service.WechatSignatureService;
import com.github.icloudpay.pay.core.service.pay.wechat.util.WechatPayConfig;
import com.github.icloudpay.pay.core.service.refund.wechat.domain.WechatRefundStatusResponse;
import com.github.wxiaoqi.security.common.admin.pay.request.QueryRefundStatusRequest;
import com.github.wxiaoqi.security.common.admin.pay.request.WechatRefundRequest;
import com.github.wxiaoqi.security.common.admin.pay.response.QueryRefundStatusResponse;
import com.github.wxiaoqi.security.common.msg.ResponseCode;
import com.github.wxiaoqi.security.common.util.FlyrayBeanUtils;

/**
 * 微信退款订单状态查询
 * @author hexufeng
 *
 */
@Service("wechatQueryRefundService")
public class WechatQueryRefundService implements QueryRefundStatusService{
	
	private static final Logger logger = (Logger) LoggerFactory.getLogger(WechatQueryRefundService.class);
	
	@Autowired
	private PayChannelConfigFeign payChannelConfigFeign;
	@Autowired
	private WechatSignatureService wechatSignatureService;
	@Autowired
	private WechatPayConfig wechatPayConfig;

	public QueryRefundStatusResponse queryRefundStatus(QueryRefundStatusRequest request)throws JAXBException {
		
		logger.info("****************调用微信退款查询状态接口开始*******************");
		QueryRefundStatusResponse queryRefundStatusResponse = new QueryRefundStatusResponse();
		
		Map<String, Object> reqMap = new HashMap<String, Object>();
    	reqMap.put("platformId", request.getPlatformId());
    	reqMap.put("merchantId", request.getMerId());
    	reqMap.put("payChannelNo", request.getPayChannelNo());
		Map<String, Object> respMap = payChannelConfigFeign.query(reqMap);
        if(!(boolean) respMap.get("success")){
			queryRefundStatusResponse.setSuccess(false);
			queryRefundStatusResponse.setCode(ResponseCode.PAYCHANNEL_CONFIGURATION_NOTEXIST.getCode());
			queryRefundStatusResponse.setMsg(ResponseCode.PAYCHANNEL_CONFIGURATION_NOTEXIST.getMessage());
			return queryRefundStatusResponse;
		}
        
        @SuppressWarnings("unchecked")
		Map<String, Object> configMap = (Map<String, Object>)respMap.get("payChannelConfigInfo");
		
		WechatRefundRequest wechatRefundRequest = new WechatRefundRequest();
		wechatRefundRequest.setAppid((String)configMap.get("outMerAccount"));// 公众账号ID
		wechatRefundRequest.setMch_id((String)configMap.get("outMerNo"));// 商户号
		wechatRefundRequest.setNonce_str(ObjectUtils.toString((new Random().nextInt() * (99999 - 10000 + 1)) + 10000));
		wechatRefundRequest.setOut_trade_no(request.getOutTradeNo());// 商户订单号
		try {
			wechatRefundRequest.setSign(wechatSignatureService.sign(wechatRefundRequest, configMap));
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		String xmlStr = null;
		try {
			xmlStr = reqData2Xml(wechatRefundRequest);
		} catch (JAXBException e) {
			logger.error("解析微信返回数据失败", e);
			queryRefundStatusResponse.setSuccess(false);
			queryRefundStatusResponse.setCode(ResponseCode.WECHAT_REFUND_FAIL.getCode());
			queryRefundStatusResponse.setMsg(ResponseCode.WECHAT_REFUND_FAIL.getMessage());
			return queryRefundStatusResponse;
		}
		CloseableHttpClient httpClient = HttpClients.createDefault();
		HttpPost post=new HttpPost(wechatPayConfig.getWechatgatewayRefundStatusUrl());
		post.addHeader("Content-Type", "text/html; charset=UTF-8");
		WechatRefundStatusResponse response = new WechatRefundStatusResponse();
		QueryRefundStatusResponse refundStatusResponse = new QueryRefundStatusResponse();

		try {
			// 设置请求参数
			Map<String, Object> param = FlyrayBeanUtils.objectToMap(wechatRefundRequest);
			if (MapUtils.isNotEmpty(param)) {
				List<NameValuePair> formparams = new ArrayList<NameValuePair>();
				for (Map.Entry<String, Object> entry : param.entrySet()) {
					// 给参数赋值
					formparams.add(new BasicNameValuePair(entry.getKey(), new String((String) entry.getValue())));
				}
				UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(formparams, Consts.UTF_8);
				post.setEntity(urlEncodedFormEntity);
			}
			HttpResponse httpResponse  = httpClient.execute(post);   
			int statusCode = httpResponse.getStatusLine().getStatusCode();
			System.out.println("状态码："+statusCode); 
			if (statusCode == HttpStatus.SC_OK) {
				HttpEntity resEntity = httpResponse.getEntity();
				String info = EntityUtils.toString(resEntity); 
				response = xmlToResponseData(new ByteArrayInputStream(info.getBytes()));
				String returnCode = response.getReturnCode();
				if (returnCode != null && !"".equals(returnCode)) {
					if ("SUCCESS".equals(returnCode)) {
						refundStatusResponse.setRefundStatus("00");//成功
						refundStatusResponse.setOutTradeNo(response.getOutTradeNo());
						refundStatusResponse.setRefundFee(response.getRefundFee());
						refundStatusResponse.setResJrnNo(response.getTransactionId());
					} else {
						refundStatusResponse.setRefundStatus("01");//失败
					}
				}
				refundStatusResponse.setSuccess(true);
				refundStatusResponse.setCode(ResponseCode.OK.getCode());
	            refundStatusResponse.setMsg(ResponseCode.OK.getMessage());
			} else {
				logger.error("发送数据失败");
				refundStatusResponse.setSuccess(false);
				refundStatusResponse.setCode(ResponseCode.SEND_DATA_FAIL.getCode());
				refundStatusResponse.setMsg(ResponseCode.SEND_DATA_FAIL.getMessage());
			}
		} catch (Exception ex) {
			logger.error("返回失败", ex);
		} finally {
			post.releaseConnection();
		}
		return refundStatusResponse;
	}

	/**
	 * 将请球参数转为Xml格式
	 * 
	 * @throws JAXBException
	 * @throws ParserConfigurationException
	 */
	private String reqData2Xml(WechatRefundRequest wechatRefundRequest) throws JAXBException {
		JAXBContext context = JAXBContext.newInstance(WechatRefundRequest.class);
		Marshaller marshaller = context.createMarshaller();
		marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");// 编码格式
		marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);// 是否格式化生成的xml串
		marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);// 是否省略xml头信息（<?xml

		ByteArrayOutputStream outputstream = new ByteArrayOutputStream();
		StreamResult result = new StreamResult(outputstream);
		marshaller.marshal(wechatRefundRequest, result);
		byte[] body = outputstream.toByteArray();

		return new String(body, Charset.forName("UTF-8"));
	}

	private WechatRefundStatusResponse xmlToResponseData(InputStream inputStream) throws JAXBException {
		Reader reader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
		JAXBContext context = JAXBContext.newInstance(WechatRefundStatusResponse.class);
		try {
			Unmarshaller unmarshaller = context.createUnmarshaller();
			return (WechatRefundStatusResponse) unmarshaller.unmarshal(reader);
		} finally {
			try {
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public Map<String, String> receiveResult(String info, Map<String, Object> configMap)
			throws ParserConfigurationException, SAXException, IOException {

		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		InputStream is = getStringStream(info);
		Document document = builder.parse(is);

		// 获取到document里面的全部结点
		NodeList allNodes = document.getFirstChild().getChildNodes();
		Node node;
		Map<String, String> paramMap = new HashMap<String, String>();
		int i = 0;
		while (i < allNodes.getLength()) {
			node = allNodes.item(i);
			if (node instanceof Element) {
				paramMap.put(node.getNodeName(), node.getTextContent());
			}
			i++;
		}
		return paramMap;
	}

	public InputStream getStringStream(String sInputString) throws UnsupportedEncodingException {
		ByteArrayInputStream tInputStringStream = null;
		if (sInputString != null && !sInputString.trim().equals("")) {
			tInputStringStream = new ByteArrayInputStream(sInputString.getBytes("UTF-8"));
		}
		return tInputStringStream;
	}

}
